package com.example.shuiyin.security;

import com.example.shuiyin.entity.User;
import com.example.shuiyin.service.JwtService;
import com.example.shuiyin.service.UserService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.security.SignatureException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.List;

@Component
@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final JwtService jwtService;
    
    @Autowired
    private UserService userService;
    
    private final boolean testMode;

    @Autowired
    public JwtAuthenticationFilter(JwtService jwtService) {
        this.jwtService = jwtService;
        this.testMode = false;
        initializeWithErrorHandling();
    }
    
    // 添加测试模式构造函数，可用于单元测试或当依赖不可用时
    public JwtAuthenticationFilter(JwtService jwtService, boolean testMode) {
        this.jwtService = jwtService;
        this.testMode = testMode;
        
        if (testMode) {
            log.warn("JWT认证过滤器以测试模式运行，认证将被禁用");
        } else {
            initializeWithErrorHandling();
        }
    }
    
    private void initializeWithErrorHandling() {
        try {
            if (jwtService == null) {
                log.error("JwtAuthenticationFilter初始化失败：JwtService为空");
                throw new IllegalArgumentException("JwtService不能为空");
            }
            
            log.info("JwtAuthenticationFilter初始化成功");
            log.debug("JwtService类型: {}", jwtService.getClass().getName());
        } catch (Exception e) {
            log.error("JwtAuthenticationFilter初始化时出错: {}", e.getMessage(), e);
            // 在初始化时不抛出异常，以确保应用可以启动
            // 过滤器将以安全模式运行，基本上跳过所有认证
        }
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        
        String requestURI = request.getRequestURI();
        
        // 如果测试模式启用或依赖缺失，跳过认证
        if (testMode || jwtService == null || userService == null) {
            log.debug("JWT过滤器以降级模式运行，跳过认证: {}", requestURI);
            chain.doFilter(request, response);
            return;
        }
        
        if (shouldSkipAuth(requestURI)) {
            log.debug("跳过认证的路径: {}", requestURI);
            chain.doFilter(request, response);
            return;
        }
        
        try {
            String token = extractToken(request);
            
            if (token != null) {
                processToken(token);
            } else {
                log.debug("请求没有JWT令牌: {}", requestURI);
            }
        } catch (ExpiredJwtException e) {
            log.warn("JWT令牌已过期: {}", e.getMessage());
        } catch (MalformedJwtException e) {
            log.warn("JWT令牌格式错误: {}", e.getMessage());
        } catch (SignatureException e) {
            log.warn("JWT签名验证失败: {}", e.getMessage());
        } catch (UnsupportedJwtException e) {
            log.warn("不支持的JWT令牌: {}", e.getMessage());
        } catch (Exception e) {
            log.error("处理JWT认证过滤器时出错: {}", e.getMessage(), e);
        } finally {
            chain.doFilter(request, response);
        }
    }
    
    private String extractToken(HttpServletRequest request) {
        try {
            String bearerToken = request.getHeader("Authorization");
            if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
                return bearerToken.substring(7);
            }
            return null;
        } catch (Exception e) {
            log.error("提取JWT令牌时出错: {}", e.getMessage(), e);
            return null;
        }
    }
    
    private void processToken(String token) {
        if (token == null || token.isEmpty()) {
            log.debug("提供的令牌为空");
            return;
        }
        
        try {
            if (jwtService.validateToken(token)) {
                Claims claims = jwtService.getClaims(token);
                if (claims == null || claims.getSubject() == null) {
                    log.warn("JWT令牌缺少主题(subject)");
                    return;
                }
                
                Long userId = Long.parseLong(claims.getSubject());
                log.debug("处理JWT令牌，用户ID: {}", userId);
                
                User user = userService.findById(userId);
                
                if (user != null) {
                    if ("ACTIVE".equals(user.getStatus())) {
                        List<SimpleGrantedAuthority> authorities = List.of(
                                new SimpleGrantedAuthority("ROLE_" + user.getRole())
                        );
                        
                        UsernamePasswordAuthenticationToken authentication = 
                                new UsernamePasswordAuthenticationToken(user, null, authorities);
                        
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                        
                        log.debug("用户 {} 认证成功，角色: {}", user.getUsername(), user.getRole());
                    } else {
                        log.warn("用户 {} 状态非活动: {}", user.getUsername(), user.getStatus());
                    }
                } else {
                    log.warn("根据令牌找不到用户, ID: {}", userId);
                }
            } else {
                log.warn("JWT令牌验证失败");
            }
        } catch (Exception e) {
            log.error("处理JWT令牌时出错: {}", e.getMessage(), e);
            SecurityContextHolder.clearContext();
            // 不再抛出异常，让过滤链继续
        }
    }
    
    private boolean shouldSkipAuth(String requestURI) {
        return requestURI.startsWith("/public") ||
               requestURI.startsWith("/api/auth") ||
               requestURI.startsWith("/v3/api-docs") ||
               requestURI.startsWith("/swagger-ui") ||
               requestURI.startsWith("/actuator") ||
               requestURI.equals("/") ||
               requestURI.startsWith("/css") ||
               requestURI.startsWith("/js") ||
               requestURI.startsWith("/images") ||
               requestURI.startsWith("/error") ||
               requestURI.startsWith("/favicon.ico");
    }
}